// 占号数据生成服务
import type { PrismaClient } from '@prisma/client'
import type {
  CreateAppointmentInput,
  IssuingAuthority,
  IssuingCountry,
} from '@shared/types/'
import type { PhoneRegion } from '@shared/utils/phone'
import { generateChinaId } from '@shared/utils/china-id'
import { generateDocumentNumber } from '@shared/utils/doc-number'
import { generateEmail } from '@shared/utils/email'
import { generatePhone } from '@shared/utils/phone'
import { pickOrGenerateUA } from '@shared/utils/user-agent'
import dayjs from 'dayjs'
import { getDatabase } from '../db/index'
import { getLogger } from '../logger/index'
import { getAppointmentService } from './appointment-service'
import 'dayjs/locale/zh-cn'

// 配置 dayjs 中文
dayjs.locale('zh-cn')

export class PlaceholderService {
  private prisma: PrismaClient
  private logger = getLogger()
  private appointmentService = getAppointmentService()
  // 近期姓名去重缓存，降低短时间内重复概率
  private recentNamesSet: Set<string> = new Set()
  private recentNamesQueue: string[] = []
  private readonly nameCacheCapacity: number = 4000

  constructor() {
    this.prisma = getDatabase()
  }

  // 生成随机驾照号码
  private generateLicenseNumber(issuingAuthority?: IssuingAuthority): string {
    // 基于 GB11643-1999，按签发机关区分广东/其他省
    const provinceKind = issuingAuthority === 'GD' ? 'GD' : 'OTH'
    return generateChinaId(provinceKind)
  }

  // 生成随机姓名（扩大字库 + 近期去重 + 限制最多三字）
  private generateRandomName(): string {
    const surnames: string[] = [
      '赵',
      '钱',
      '孙',
      '李',
      '周',
      '吴',
      '郑',
      '王',
      '冯',
      '陈',
      '褚',
      '卫',
      '蒋',
      '沈',
      '韩',
      '杨',
      '朱',
      '秦',
      '尤',
      '许',
      '何',
      '吕',
      '施',
      '张',
      '孔',
      '曹',
      '严',
      '华',
      '金',
      '魏',
      '陶',
      '姜',
      '戚',
      '谢',
      '邹',
      '喻',
      '柏',
      '水',
      '窦',
      '章',
      '云',
      '苏',
      '潘',
      '葛',
      '奚',
      '范',
      '彭',
      '郎',
      '鲁',
      '韦',
      '昌',
      '马',
      '苗',
      '凤',
      '花',
      '方',
      '俞',
      '任',
      '袁',
      '柳',
      '唐',
      '罗',
      '薛',
      '伍',
      '余',
      '米',
      '贝',
      '姚',
      '孟',
      '顾',
      '尹',
      '江',
      '钟',
      '邱',
      '熊',
      '纪',
      '舒',
      '屈',
      '项',
      '祝',
      '董',
      '梁',
      '杜',
      '阮',
      '蓝',
      '闵',
      '席',
      '季',
      '麻',
      '贾',
      '路',
      '娄',
      '危',
      '江',
      '童',
      '颜',
      '梅',
      '盛',
      '林',
      '钟',
      '徐',
      '邵',
      '高',
      '夏',
      '蔡',
      '田',
      '樊',
      '胡',
      '凌',
      '霍',
    ]
    const givenChars: string[] = [
      '伟',
      '芳',
      '娜',
      '秀英',
      '敏',
      '静',
      '丽',
      '强',
      '磊',
      '军',
      '洋',
      '勇',
      '艳',
      '杰',
      '娟',
      '涛',
      '明',
      '超',
      '秀兰',
      '霞',
      '慧',
      '丹',
      '璐',
      '倩',
      '蕾',
      '雪',
      '佳',
      '鑫',
      '鑫',
      '佳',
      '玉',
      '梅',
      '琳',
      '艳',
      '斌',
      '俊',
      '飞',
      '宇',
      '豪',
      '博',
      '瑞',
      '浩',
      '鑫',
      '志',
      '晨',
      '凯',
      '洁',
      '宁',
      '鑫',
      '颖',
      '欣',
      '楠',
      '婧',
      '涵',
      '璇',
      '佳',
      '钰',
      '妍',
      '怡',
      '露',
      '菲',
      '璐',
      '然',
      '芸',
      '瑜',
      '瑶',
      '琪',
      '钦',
      '桐',
      '芸',
      '煜',
      '宸',
      '泽',
      '航',
      '一',
      '可',
      '乐',
      '凡',
      '伊',
      '沐',
      '梓',
      '梓',
      '子',
      '若',
      '诗',
      '依',
      '舒',
      '柔',
      '雅',
      '欣',
      '曼',
      '晨',
      '语',
      '晨',
      '忆',
      '可',
      '嘉',
      '桐',
      '霖',
      '翌',
      '源',
      '衍',
      '恒',
      '承',
      '彦',
      '淇',
      '茜',
      '一诺',
      '佳怡',
      '梓涵',
      '梦瑶',
      '语桐',
      '欣怡',
      '子涵',
      '思怡',
      '子萱',
      '雨桐',
      '佳欣',
      '梓萱',
      '靖雯',
      '婉婷',
      '静怡',
      '美琳',
      '雅静',
      '雪儿',
      '锦程',
      '昕怡',
      '紫涵',
      '悦然',
      '梓童',
      '沛然',
      '奕辰',
      '宇轩',
      '子豪',
      '浩然',
      '梓辰',
      '予欣',
      '嘉懿',
      '君豪',
      '思源',
      '景天',
      '嘉禾',
      '锦程',
      '钰轩',
    ]

    const pick = (arr: string[]) => arr[Math.floor(Math.random() * arr.length)]
    const givenLen1 = givenChars.filter(c => c.length === 1)
    const givenLen2 = givenChars.filter(c => c.length === 2)
    const tryCompose = (): string => {
      const surname = pick(surnames) // 目前姓氏均为单字
      // 35% 选 2 字名（总长 3）
      if (Math.random() < 0.35 && givenLen2.length > 0) {
        const g = pick(givenLen2)
        return `${surname}${g}`
      }
      // 50% 选 1+1 的双字名（总长 3）
      if (Math.random() < 0.5 && givenLen1.length >= 2) {
        const g1 = pick(givenLen1)
        const g2 = pick(givenLen1)
        return `${surname}${g1}${g2}`
      }
      // 兜底：优先 1 字名，否则 2 字名；最终截断至 3 字
      const base = (givenLen1.length > 0 ? pick(givenLen1) : (givenLen2.length > 0 ? pick(givenLen2) : pick(givenChars)))
      const name = `${surname}${base}`
      return name.length <= 3 ? name : name.slice(0, 3)
    }

    // 最多尝试 8 次避免近期重复
    for (let i = 0; i < 8; i++) {
      const name = tryCompose()
      if (!this.recentNamesSet.has(name)) {
        this.recentNamesSet.add(name)
        this.recentNamesQueue.push(name)
        if (this.recentNamesQueue.length > this.nameCacheCapacity) {
          const old = this.recentNamesQueue.shift()
          if (old)
            this.recentNamesSet.delete(old)
        }
        return name
      }
    }
    // 兜底：返回最后一次生成（再保证总长 <= 3）
    const last = tryCompose()
    return last.length <= 3 ? last : last.slice(0, 3)
  }

  // 生成随机邮箱（共享工具）
  private generateRandomEmail(baseEmail?: string, mode?: { use2925?: boolean }): string {
    return generateEmail({ fixed: baseEmail, use2925: mode?.use2925 })
  }

  // 生成随机电话号码（CN 用大陆手机，其他用香港手机）
  private generateRandomPhone(issuingCountry?: IssuingCountry): string {
    const region: PhoneRegion = issuingCountry === 'CN' ? 'CN' : 'HK'
    return generatePhone({ region })
  }

  // 已弃用的应用层查重：保留位置说明，逻辑迁移为落库唯一约束 + 冲突重试

  // 生成占号数据候选（唯一性依赖数据库约束与创建阶段的重试）
  private async generateUniqueData(_maxAttempts: number = 100, opts?: {
    issuing_authority?: IssuingAuthority
    email?: { fixed?: string, use2925?: boolean }
    issuing_country?: IssuingCountry
  }): Promise<{
    passport_number: string
    license_number: string
    full_name: string
    email: string
    phone_number: string
  }> {
    const passportNumber = generateDocumentNumber({ type: 'random', twoLetterPrefix: 'random' })
    const licenseNumber = this.generateLicenseNumber(opts?.issuing_authority)
    return {
      passport_number: passportNumber,
      license_number: licenseNumber,
      full_name: this.generateRandomName(),
      email: this.generateRandomEmail(opts?.email?.fixed, { use2925: opts?.email?.use2925 }),
      phone_number: this.generateRandomPhone(opts?.issuing_country || 'CN'),
    }
  }

  // 生成单个占号数据
  async generateSinglePlaceholder(options: {
    issuing_country?: IssuingCountry
    issuing_authority?: IssuingAuthority
    service_type?: string
    office_code?: string
    priority?: number
    preferred_dates?: string[]
    preferred_times?: string[]
    remarks?: string
    email_mode?: { fixed?: string, use2925?: boolean }
  } = {}): Promise<number> {
    try {
      const maxCreateAttempts = 10
      let lastError: any = null
      for (let attempt = 0; attempt < maxCreateAttempts; attempt++) {
        const candidate = await this.generateUniqueData(1, {
          issuing_authority: options.issuing_authority,
          issuing_country: options.issuing_country,
          email: options.email_mode,
        })

        const appointmentData: CreateAppointmentInput = {
          ...candidate,
          issuing_country: options.issuing_country || 'CN',
          issuing_authority: options.issuing_authority || 'GD',
          service_type: options.service_type || 'DI',
          office_code: options.office_code || 'HKLO',
          priority: options.priority || 1,
          preferred_dates: options.preferred_dates,
          preferred_times: options.preferred_times,
          remarks: options.remarks || '系统生成的占号数据',
          is_placeholder: true,
          user_agent: pickOrGenerateUA(),
        }

        try {
          const appointment = await this.appointmentService.createAppointment(appointmentData, { asPlaceholder: true })
          this.logger.info(`✅ 生成占号数据成功: ${appointment.sequence_number}`)
          return appointment.id
        }
        catch (err: any) {
          const msg = String(err?.message || '')
          const isDuplicateCombo = msg.includes('该护照号和驾照号的记录已存在')
            || (err?.code === 'P2002' && Array.isArray(err?.meta?.target) && err.meta.target.includes('passport_number') && err.meta.target.includes('license_number'))
          if (isDuplicateCombo) {
            // 碰到唯一约束冲突，重试生成新候选
            lastError = err
            await new Promise(r => setTimeout(r, 5 + Math.floor(Math.random() * 20)))
            continue
          }
          // 其他错误直接抛出
          throw err
        }
      }
      // 多次重试仍失败
      throw lastError || new Error('创建占号数据失败（多次重试后仍冲突）')
    }
    catch (error) {
      this.logger.error('生成占号数据失败:', error)
      throw error
    }
  }

  // 批量生成占号数据
  async generateBatchPlaceholders(options: {
    count: number
    issuing_country?: IssuingCountry
    issuing_authority?: IssuingAuthority
    service_type?: string
    office_code?: string
    priority?: number
    preferred_dates?: string[]
    preferred_times?: string[]
    remarks?: string
    concurrent_limit?: number
    email_mode?: { fixed?: string, use2925?: boolean }
  }): Promise<{
    success: boolean
    total_count: number
    success_count: number
    failed_count: number
    generated_ids: number[]
    errors: Array<{ index: number, message: string }>
  }> {
    const result = {
      success: true,
      total_count: options.count,
      success_count: 0,
      failed_count: 0,
      generated_ids: [] as number[],
      errors: [] as Array<{ index: number, message: string }>,
    }

    try {
      this.logger.info(`🚀 开始批量生成 ${options.count} 个占号数据`)

      const concurrentLimit = Math.min(options.concurrent_limit || 5, 10)

      for (let i = 0; i < options.count; i += concurrentLimit) {
        const batchEnd = Math.min(i + concurrentLimit, options.count)
        const currentBatchIndex = Math.floor(i / concurrentLimit) + 1

        const batchPromises: Array<Promise<{ index: number, id?: number, error?: unknown }>> = []
        for (let j = i; j < batchEnd; j++) {
          const p = this.generateSinglePlaceholder({
            issuing_country: options.issuing_country,
            issuing_authority: options.issuing_authority,
            service_type: options.service_type,
            office_code: options.office_code,
            priority: options.priority,
            preferred_dates: options.preferred_dates,
            preferred_times: options.preferred_times,
            remarks: `${options.remarks || '系统生成的占号数据'} - 批次 ${currentBatchIndex}`,
            email_mode: options.email_mode,
          })
            .then(id => ({ index: j, id }))
            .catch(error => ({ index: j, error }))
          batchPromises.push(p)
        }

        const batchResults = await Promise.all(batchPromises)

        for (const r of batchResults) {
          if (r.id !== undefined) {
            result.success_count++
            result.generated_ids.push(r.id as number)
          }
          else {
            result.failed_count++
            result.errors.push({ index: r.index, message: (r as any).error?.message || String((r as any).error || '未知错误') })
          }
        }

        if (batchEnd < options.count) {
          await new Promise(resolve => setTimeout(resolve, 100))
        }
      }

      if (result.failed_count > 0) {
        result.success = false
      }

      this.logger.info(`✅ 批量生成占号数据完成: 成功 ${result.success_count}，失败 ${result.failed_count}`)
      return result
    }
    catch (error: unknown) {
      this.logger.error('批量生成占号数据失败:', error)
      result.success = false
      result.failed_count = options.count
      result.errors = [{ index: -1, message: (error instanceof Error ? error.message : String(error)) }]
      return result
    }
  }

  // 为特定预约生成配套占号数据
  async generatePlaceholdersForAppointment(
    appointmentId: number,
    count: number,
  ): Promise<{
    success: boolean
    generated_count: number
    generated_ids: number[]
  }> {
    try {
      // 获取原始预约记录
      const originalAppointment = await this.appointmentService.getAppointment(appointmentId)
      if (!originalAppointment) {
        throw new Error('原始预约记录不存在')
      }

      // 解析偏好数据（安全解析）
      const safeParse = <T = any>(s?: string | null): T | undefined => {
        if (!s)
          return undefined
        try {
          const v = JSON.parse(s)
          return v as T
        }
        catch {
          this.logger.warn('偏好数据 JSON 解析失败，已忽略')
          return undefined
        }
      }
      const preferredDates = safeParse<string[]>(originalAppointment.preferred_dates as any)
      const preferredTimes = safeParse<string[]>(originalAppointment.preferred_times as any)

      // 生成占号数据
      const result = await this.generateBatchPlaceholders({
        count,
        issuing_country: originalAppointment.issuing_country as IssuingCountry,
        issuing_authority: originalAppointment.issuing_authority as IssuingAuthority,
        service_type: originalAppointment.service_type,
        office_code: originalAppointment.office_code,
        priority: Math.max(1, originalAppointment.priority - 1), // 占号优先级稍低
        preferred_dates: preferredDates,
        preferred_times: preferredTimes,
        remarks: `为预约 ${originalAppointment.sequence_number} 生成的配套占号数据`,
        concurrent_limit: 3,
      })

      this.logger.info(`✅ 为预约 ${originalAppointment.sequence_number} 生成了 ${result.success_count} 个配套占号数据`)

      return {
        success: result.success,
        generated_count: result.success_count,
        generated_ids: result.generated_ids,
      }
    }
    catch (error) {
      this.logger.error('为预约生成配套占号数据失败:', error)
      throw error
    }
  }

  // 获取占号数据统计
  async getPlaceholderStatistics(): Promise<{
    total_placeholders: number
    active_placeholders: number
    today_generated: number
    by_service_type: Record<string, number>
    by_office_code: Record<string, number>
  }> {
    try {
      const [
        totalPlaceholders,
        activePlaceholders,
        todayGenerated,
        byServiceType,
        byOfficeCode,
      ] = await Promise.all([
        this.prisma.appointment_management.count({
          where: { is_placeholder: true },
        }),
        this.prisma.appointment_management.count({
          where: {
            is_placeholder: true,
            appointment_status: 'pending',
          },
        }),
        this.prisma.appointment_management.count({
          where: {
            is_placeholder: true,
            created_at: {
              gte: dayjs().startOf('day').toDate(),
            },
          },
        }),
        this.prisma.appointment_management.groupBy({
          by: ['service_type'],
          where: { is_placeholder: true },
          _count: { id: true },
        }),
        this.prisma.appointment_management.groupBy({
          by: ['office_code'],
          where: { is_placeholder: true },
          _count: { id: true },
        }),
      ])

      const serviceTypeStats: Record<string, number> = {}
      byServiceType.forEach((item) => {
        serviceTypeStats[item.service_type] = item._count.id
      })

      const officeCodeStats: Record<string, number> = {}
      byOfficeCode.forEach((item) => {
        officeCodeStats[item.office_code] = item._count.id
      })

      return {
        total_placeholders: totalPlaceholders,
        active_placeholders: activePlaceholders,
        today_generated: todayGenerated,
        by_service_type: serviceTypeStats,
        by_office_code: officeCodeStats,
      }
    }
    catch (error) {
      this.logger.error('获取占号数据统计失败:', error)
      throw error
    }
  }

  // 清理指定的占号数据
  async cleanupPlaceholdersByIds(placeholderIds: number[]): Promise<number> {
    try {
      const result = await this.prisma.appointment_management.deleteMany({
        where: {
          id: { in: placeholderIds },
          is_placeholder: true,
        },
      })

      this.logger.info(`🧹 清理了 ${result.count} 个指定的占号数据`)
      return result.count
    }
    catch (error) {
      this.logger.error('清理指定占号数据失败:', error)
      throw error
    }
  }

  // 释放占号数据（转为已取消状态，保留记录）
  async releasePlaceholdersByIds(placeholderIds: number[]): Promise<number> {
    try {
      const result = await this.prisma.appointment_management.updateMany({
        where: {
          id: { in: placeholderIds },
          is_placeholder: true,
          appointment_status: 'pending',
        },
        data: {
          appointment_status: 'cancelled',
          error_message: '占号已释放',
        },
      })

      this.logger.info(`🔓 释放了 ${result.count} 个占号数据`)
      return result.count
    }
    catch (error) {
      this.logger.error('释放占号数据失败:', error)
      throw error
    }
  }
}

// 创建全局服务实例
let placeholderService: PlaceholderService | null = null

export function getPlaceholderService(): PlaceholderService {
  if (!placeholderService) {
    placeholderService = new PlaceholderService()
  }
  return placeholderService
}
